home *** CD-ROM | disk | FTP | other *** search
/ FishMarket 1.0 / FishMarket v1.0.iso / fishies / 326-350 / disk_327 / msh / src / pack.c < prev    next >
C/C++ Source or Header  |  1992-05-06  |  26KB  |  1,056 lines

  1. /*-
  2.  * $Id: pack.c,v 1.3 90/02/03 17:02:05 Rhialto Exp $
  3.  * $Log:    pack.c,v $
  4.  * Revision 1.3  90/02/03  17:02:05  Rhialto
  5.  * Add error checking wrt dosalloc()
  6.  * 
  7.  * Revision 1.2  89/12/17  23:06:54  Rhialto
  8.  * Add ACTION_SET_PROTECT
  9.  *
  10.  * Revision 1.1  89/12/17  19:53:24  Rhialto
  11.  * Initial revision
  12.  *
  13.  *
  14.  *  Originally:
  15.  *
  16.  *    DOSDEVICE.C        V1.10   2 November 1987
  17.  *
  18.  *    EXAMPLE DOS DEVICE DRIVER FOR AZTEC.C    PUBLIC DOMAIN.
  19.  *
  20.  *    By Matthew Dillon.
  21.  *
  22.  *  This has been stripped and refilled with messydos code
  23.  *  by Olaf Seibert.
  24.  *
  25.  *  This code is (C) Copyright 1989 by Olaf Seibert. All rights reserved. May
  26.  *  not be used or copied without a licence.
  27.  *
  28.  *  Please note that we are NOT pure, so if you wish to mount
  29.  *  multiple MSDOS units, you must use different copies of this driver.
  30.  *
  31.  *  This file forms the interface between the actual handler code and all
  32.  *  AmigaDOS requirements. It shields it from ugly stuff like BPTRs, BSTRs,
  33.  *  FileLocks, FileHandles and VolumeNodes (in the form of DeviceLists).
  34.  *  Also, most protection against non-inserted disks is done here.
  35. -*/
  36.  
  37. #include "dos.h"
  38. #include "han.h"
  39.  
  40. #ifdef DEBUG
  41. #   define    debug(x)  dbprintf x
  42. #else
  43. #   define    debug(x)
  44. #endif
  45.  
  46. /*
  47.  * Since this code might be called several times in a row without being
  48.  * unloaded, you CANNOT ASSUME GLOBALS HAVE BEEN ZERO'D!!  This also goes
  49.  * for any global/static assignments that might be changed by running the
  50.  * code.
  51.  */
  52.  
  53. PORT           *DosPort;    /* Our DOS port... */
  54. DEVNODE        *DevNode;    /* Our DOS node.. created by DOS for us */
  55. DEVLIST        *VolNode;    /* Device List structure for our volume
  56.                  * node */
  57.  
  58. void           *SysBase;    /* EXEC library base */
  59. DOSLIB           *DOSBase;    /* DOS library base for debug process */
  60. long        PortMask;    /* The signal mask for our DosPort */
  61. long        WaitMask;    /* The signal mask to wait for */
  62. short        DiskChanged;    /* Set by disk change interrupt */
  63. short        Inhibited;    /* Are we inhibited (ACTION_INHIBIT)? */
  64. long        UnitNr;     /* From */
  65. char           *DevName;    /*   the */
  66. ulong        DevFlags;    /*     mountlist */
  67. PACKET           *DosPacket;    /* For the SystemRequest pr_WindowPtr */
  68.  
  69. void ChangeIntHand(), DiskChange();
  70. void NewVolNodeName(), NewVolNodeDate();
  71.  
  72. struct Interrupt ChangeInt = {
  73.     { 0 },            /* is_Node */
  74.     0,                /* is_Data */
  75.     ChangeIntHand,        /* is_Code */
  76. };
  77.  
  78. /*
  79.  * Don't call the entry point main().  This way, if you make a mistake
  80.  * with the compile options you'll get a link error.
  81.  */
  82.  
  83. void
  84. messydoshandler()
  85. {
  86.     register PACKET *packet;
  87.     MSG        *msg;
  88.     byte        notdone;
  89.     long        OpenCount;        /* How many open files/locks there are */
  90.  
  91.     /*
  92.      * Initialize all global variables.  SysBase MUST be initialized
  93.      * before we can make Exec calls.  AbsExecBase is a library symbol
  94.      * referencing absolute memory location 4.
  95.      */
  96.  
  97.     SysBase = AbsExecBase;
  98.     DOSBase = OpenLibrary("dos.library", 0L);
  99.  
  100. #ifdef DEBUG
  101.     /*
  102.      * Initialize debugging code as soon as possible. Only SysBase and
  103.      * DOSBase are required.
  104.      */
  105.  
  106.     dbinit();
  107. #endif                /* DEBUG */
  108.  
  109.     DosPort = &((struct Process *)FindTask(NULL))->pr_MsgPort;
  110.  
  111.     WaitPort(DosPort);      /* Get Startup Packet  */
  112.     msg = GetMsg(DosPort);
  113.     packet = (PACKET *) msg->mn_Node.ln_Name;
  114.  
  115.  
  116.     DevNode = BTOC(PArg3);
  117.     {
  118.     struct FileSysStartupMsg *fssm;
  119.     ulong *environ;
  120.  
  121.     DevName = "messydisk.device";
  122.     UnitNr = 0;
  123.     DevFlags = 0;
  124.  
  125.     MaxCache = 5;
  126.     BufMemType = MEMF_PUBLIC;
  127.     Disk.nsides = MS_NSIDES;
  128.     Disk.spt = MS_SPT;
  129.     Disk.bps = MS_BPS;
  130.     Disk.lowcyl = 0;
  131.  
  132.     if (fssm = (struct FileSysStartupMsg *)BTOC(DevNode->dn_Startup)) {
  133.                     /* Same as BTOC(packet->dp_Arg2) */
  134.         UnitNr = fssm->fssm_Unit;
  135.         if (fssm->fssm_Device)
  136.         DevName = (char *)BTOC(fssm->fssm_Device)+1;
  137.         DevFlags = fssm->fssm_Flags;
  138.  
  139.         if (environ = BTOC(fssm->fssm_Environ)) {
  140.         debug(("environ size %ld\n", environ[0]));
  141. #define get(xx,yy)  if (environ[0] >= yy) xx = environ[yy];
  142.  
  143.         get(MaxCache, DE_NUMBUFFERS);
  144.         get(BufMemType, DE_MEMBUFTYPE);
  145.         get(Disk.nsides, DE_NUMHEADS);
  146.         get(Disk.spt, DE_BLKSPERTRACK);
  147.         get(Disk.bps, DE_SIZEBLOCK);
  148.         Disk.bps *= 4;
  149.         debug(("Disk.bps %d\n", Disk.bps));
  150.         get(Disk.lowcyl, DE_LOWCYL);
  151. #undef get
  152.         }
  153.     }
  154.     Disk.lowcyl *= (long)MS_BPS * Disk.spt * Disk.nsides;
  155.     }
  156.  
  157.     if (DOSBase && HanOpenUp()) {
  158.     /*
  159.      * Loading DevNode->dn_Task causes DOS *NOT* to startup a new
  160.      * instance of the device driver for every reference.    E.G. if
  161.      * you were writing a CON: device you would want this field to be
  162.      * NULL.
  163.      */
  164.  
  165.     DevNode->dn_Task = DosPort;
  166.  
  167.     PRes1 = DOSTRUE;
  168.     PRes2 = 0;
  169.     } else {            /* couldn't open dos.library  */
  170.     PRes1 = DOSFALSE;
  171.     PRes2 = ERROR_NO_FREE_STORE;    /* no better message available */
  172.     returnpacket(packet);
  173.     goto exit;        /* exit process    */
  174.     }
  175.     returnpacket(packet);
  176.  
  177.     /* Initialize some more global variables    */
  178.  
  179.     PortMask = 1L << DosPort->mp_SigBit;
  180.     VolNode = NULL;
  181.     OpenCount = 0;
  182.     Inhibited = 0;
  183.  
  184.     /* Get the first real packet       */
  185.     WaitPort(DosPort);
  186.     msg = GetMsg(DosPort);
  187.     notdone = 1;
  188.     WaitMask = PortMask | (1L << DiskReplyPort->mp_SigBit);
  189.     TDAddChangeInt(&ChangeInt);
  190.     DiskInserted(WhichDiskInserted());
  191.  
  192.     goto entry;
  193.  
  194.     /*
  195.      * Here begins the endless loop, waiting for requests over our message
  196.      * port and executing them.  Since requests are sent over the message
  197.      * port in our device and volume nodes, we must not use our Process
  198.      * message port for this: this precludes being able to call DOS
  199.      * functions ourselves.
  200.      */
  201.  
  202. top:
  203.     for (notdone = 1; notdone;) {
  204.     Wait(WaitMask);
  205.     if (DiskChanged)
  206.         DiskChange();
  207.     while (msg = GetMsg(DosPort)) {
  208.         byte        buf[256];    /* Max length of BCPL strings is
  209.                      * 255 + 1 for \0. */
  210.  
  211.     entry:
  212.         if (DiskChanged)
  213.         DiskChange();
  214.         packet = (PACKET *) msg->mn_Node.ln_Name;
  215.         PRes1 = DOSFALSE;
  216.         PRes2 = 0;
  217.         error = 0;
  218.         debug(("Packet: %3ld %08lx %08lx %08lx %10s\n",
  219.              PType, PArg1, PArg2, PArg3, typetostr(PType)));
  220.  
  221.         DosPacket = packet;     /* For the System Requesters */
  222.         switch (PType) {
  223.         case ACTION_DIE:        /* attempt to die?  */
  224.         notdone = 0;        /* try to die     */
  225.         break;
  226.         case ACTION_CURRENT_VOLUME: /* -              VolNode,UnitNr */
  227.         PRes1 = (long) CTOB(VolNode);
  228.         PRes2 = UnitNr;
  229.         break;
  230.         case ACTION_LOCATE_OBJECT:    /* Lock,Name,Mode    Lock         */
  231.         {
  232.             register struct FileLock *newlock;
  233.             struct FileLock *lock;
  234.             struct MSFileLock *msfl;
  235.             long        lockmode;
  236.  
  237.             lock = BTOC(PArg1);
  238.             if (CheckRead(lock))
  239.             break;
  240.             btos(PArg2, buf);
  241.             if ((lockmode = PArg3) != EXCLUSIVE_LOCK)
  242.             lockmode = SHARED_LOCK;
  243.             msfl = MSLock(lock ? lock->fl_Key : NULL,
  244.                   buf,
  245.                   lockmode);
  246.             if (msfl) {
  247.             if (newlock = NewFileLock(msfl, lock)) {
  248.                 newlock->fl_Access = lockmode;
  249.                 PRes1 = (long) CTOB(newlock);
  250.                 OpenCount++;
  251.             } else
  252.                 MSUnLock(msfl);
  253.             }
  254.         }
  255.         break;
  256.         case ACTION_RENAME_DISK:    /* BSTR:NewName        Bool      */
  257.         if (CheckWrite(NULL))
  258.             break;
  259.         btos(PArg1, buf);
  260.         buf[31] = '\0';
  261.         if (PRes1 = MSRelabel(buf))
  262.             NewVolNodeName();
  263.         break;
  264.         case ACTION_FREE_LOCK:    /* Lock            Bool      */
  265.         {
  266.             struct FileLock *lock;
  267.             struct MSFileLock *msfl;
  268.  
  269.             PRes1 = DOSTRUE;
  270.             lock = BTOC(PArg1);
  271.             if (lock == NULL)
  272.             break;
  273.  
  274.             msfl = (struct MSFileLock *)lock->fl_Key;
  275.             FreeFileLock(lock); /* may remove last lock on volume */
  276.             MSUnLock(msfl);     /* may call MayFreeVolNode */
  277.             OpenCount--;
  278.         }
  279.         break;
  280.         case ACTION_DELETE_OBJECT:    /* Lock,Name        Bool         */
  281.         {
  282.             struct FileLock *lock;
  283.  
  284.             lock = BTOC(PArg1);
  285.             if (CheckWrite(lock))
  286.             break;
  287.             btos(PArg2, buf);
  288.             PRes1 = MSDeleteFile(lock ? lock->fl_Key : NULL,
  289.                      buf);
  290.         }
  291.         break;
  292.         case ACTION_RENAME_OBJECT:    /* SLock,SName,DLock,DName   Bool    */
  293.         {
  294.             struct FileLock *slock, *dlock;
  295.             char         buf2[256];
  296.  
  297.             slock = BTOC(PArg1);
  298.             dlock = BTOC(PArg3);
  299.             if (CheckWrite(slock) || CheckWrite(dlock))
  300.             break;
  301.             btos(PArg2, buf);
  302.             btos(PArg4, buf2);
  303.             PRes1 = MSRename(slock ? slock->fl_Key : NULL,
  304.                      buf,
  305.                      dlock ? dlock->fl_Key : NULL,
  306.                      buf2);
  307.         }
  308.         break;
  309.         case ACTION_MORECACHE:    /* #BufsToAdd           Bool      */
  310.         if ((MaxCache += (short) PArg1) <= 0) {
  311.             MaxCache = 1;
  312.         } else
  313.             PRes1 = DOSTRUE;
  314.         debug(("Now %d cache sectors\n", MaxCache));
  315.         break;
  316.         case ACTION_COPY_DIR:    /* Lock            Lock      */
  317.         {
  318.             register struct FileLock *newlock;
  319.             struct FileLock *lock;
  320.             struct MSFileLock *msfl;
  321.  
  322.             lock = BTOC(PArg1);
  323.  
  324.             msfl = MSDupLock(lock ? lock->fl_Key : NULL);
  325.  
  326.             if (msfl) {
  327.             if (newlock = NewFileLock(msfl, lock)) {
  328.                 newlock->fl_Access =
  329.                 lock ? lock->fl_Access : SHARED_LOCK;
  330.                 PRes1 = (long) CTOB(newlock);
  331.                 OpenCount++;
  332.             } else
  333.                 MSUnLock(msfl);
  334.             }
  335.         }
  336.         break;
  337.         case ACTION_SET_PROTECT:    /* -,Lock,Name,Mask       Bool      */
  338.         {
  339.             struct FileLock *lock;
  340.  
  341.             lock = BTOC(PArg2);
  342.             if (CheckWrite(lock))
  343.             break;
  344.             btos(PArg3, buf);
  345.             PRes1 = MSSetProtect(lock ? lock->fl_Key : NULL, buf, PArg4);
  346.         }
  347.         break;
  348.         case ACTION_CREATE_DIR:    /* Lock,Name        Lock         */
  349.         {
  350.             register struct FileLock *newlock;
  351.             struct FileLock *lock;
  352.             struct MSFileLock *msfl;
  353.  
  354.             lock = BTOC(PArg1);
  355.             if (CheckWrite(lock))
  356.             break;
  357.             btos(PArg2, buf);
  358.  
  359.             msfl = MSCreateDir(lock ? lock->fl_Key : NULL, buf);
  360.  
  361.             if (msfl) {
  362.             if (newlock = NewFileLock(msfl, lock)) {
  363.                 newlock->fl_Access = SHARED_LOCK;
  364.                 PRes1 = (long) CTOB(newlock);
  365.                 OpenCount++;
  366.             } else
  367.                 MSUnLock(msfl);
  368.             }
  369.         }
  370.         break;
  371.         case ACTION_EXAMINE_OBJECT: /* Lock,Fib           Bool         */
  372.         {
  373.             struct FileLock *lock;
  374.  
  375.             lock = BTOC(PArg1);
  376.             if (CheckRead(lock))
  377.             break;
  378.             PRes1 = MSExamine(lock ? lock->fl_Key : NULL, BTOC(PArg2));
  379.         }
  380.         break;
  381.         case ACTION_EXAMINE_NEXT:    /* Lock,Fib           Bool         */
  382.         {
  383.             struct FileLock *lock;
  384.  
  385.             lock = BTOC(PArg1);
  386.             if (CheckRead(lock))
  387.             break;
  388.             PRes1 = MSExNext(lock ? lock->fl_Key : NULL, BTOC(PArg2));
  389.         }
  390.         break;
  391.         case ACTION_DISK_INFO:    /* InfoData           Bool:TRUE     */
  392.         PRes1 = MSDiskInfo(BTOC(PArg1));
  393.         break;
  394.         case ACTION_INFO:    /* Lock,InfoData           Bool:TRUE     */
  395.         if (CheckRead(BTOC(PArg1)))
  396.             break;
  397.         PRes1 = MSDiskInfo(BTOC(PArg2));
  398.         break;
  399.         case ACTION_FLUSH:        /* writeout bufs, disk motor off     */
  400.         MSUpdate(1);
  401.         break;
  402. /*        case ACTION_SET_COMMENT:    /* -,Lock,Name,Comment       Bool      */
  403.         case ACTION_PARENT: /* Lock                ParentLock    */
  404.         {
  405.             register struct FileLock *newlock;
  406.             struct FileLock *lock;
  407.             struct MSFileLock *msfl;
  408.             long mode;
  409.  
  410.             lock = BTOC(PArg1);
  411.  
  412.             msfl = MSParentDir(lock ? lock->fl_Key : NULL);
  413.  
  414.             if (msfl) {
  415.             if (newlock = NewFileLock(msfl, lock)) {
  416.                 newlock->fl_Access = SHARED_LOCK;
  417.                 PRes1 = (long) CTOB(newlock);
  418.                 OpenCount++;
  419.             } else
  420.                 MSUnLock(msfl);
  421.             }
  422.         }
  423.         break;
  424.         case ACTION_INHIBIT:    /* Bool            Bool      */
  425.         if (Inhibited = PArg1) {
  426.             DiskRemoved();
  427.         } else { /* Fall through to ACTION_DISK_CHANGE: */
  428.         case ACTION_DISK_CHANGE:    /* ?               ?         */
  429.             DiskChange();
  430.         }
  431.         PRes1 = DOSTRUE;
  432.         break;
  433.         case ACTION_SET_DATE: /* -,Lock,Name,CPTRDateStamp       Bool      */
  434.         {
  435.             struct FileLock *lock;
  436.  
  437.             lock = BTOC(PArg2);
  438.             if (CheckWrite(lock))
  439.             break;
  440.             btos(PArg3, buf);
  441.             PRes1 = MSSetDate(lock ? lock->fl_Key : NULL,
  442.                       buf,
  443.                       PArg4);
  444.         }
  445.         break;
  446.         case ACTION_READ:    /* FHArg1,CPTRBuffer,Length      ActLength  */
  447.         if (CheckRead(NULL)) {
  448.             PRes1 = -1;
  449.         } else
  450.             PRes1 = MSRead(PArg1, PArg2, PArg3);
  451.         break;
  452.         case ACTION_WRITE:    /* FHArg1,CPTRBuffer,Length      ActLength  */
  453.         if (CheckWrite(NULL)) {
  454.             PRes1 = -1;
  455.         } else
  456.             PRes1 = MSWrite(PArg1, PArg2, PArg3);
  457.         break;
  458.         case ACTION_OPENNEW:    /* FileHandle,Lock,Name    Bool      */
  459.         {
  460.             struct MSFileHandle *msfh;
  461.             struct FileHandle *fh;
  462.             struct FileLock *lock;
  463.  
  464.             if (CheckWrite(BTOC(PArg2)))
  465.             break;
  466.         case ACTION_OPENRW:     /* FileHandle,Lock,Name    Bool      */
  467.         case ACTION_OPENOLD:    /* FileHandle,Lock,Name    Bool      */
  468.  
  469.             fh = BTOC(PArg1);
  470.             lock = BTOC(PArg2);
  471.             if (CheckRead(lock))
  472.             break;
  473.             btos(PArg3, buf);
  474.             debug(("'%s' ", buf));
  475.             msfh = MSOpen(lock ? lock->fl_Key : NULL,
  476.                   buf,
  477.                   PType);
  478.             if (msfh) {
  479.             fh->fh_Arg1 = (long) msfh;
  480.             PRes1 = DOSTRUE;
  481.             OpenCount++;
  482.             }
  483.         }
  484.         break;
  485.         case ACTION_CLOSE:    /* FHArg1              Bool:TRUE  */
  486.         MSClose(PArg1);
  487.         PRes1 = DOSTRUE;
  488.         OpenCount--;
  489.         break;
  490.         case ACTION_SEEK:    /* FHArg1,Position,Mode      OldPosition */
  491.         if (CheckRead(NULL)) {
  492.             PRes1 = -1;
  493.         } else
  494.             PRes1 = MSSeek(PArg1, PArg2, PArg3);
  495.         break;
  496.         /*
  497.          * A few other packet types which we do not support
  498.          */
  499. /*        case ACTION_WAIT_CHAR:    /* Timeout, ticks       Bool      */
  500. /*        case ACTION_RAWMODE:    /* Bool(-1:RAW 0:CON)      OldState  */
  501.         default:
  502.         error = ERROR_ACTION_NOT_KNOWN;
  503.         break;
  504.         } /* end switch */
  505.         if (packet) {
  506.         if (error) {
  507.             debug(("ERR=%d\n", error));
  508.             PRes2 = error;
  509.         }
  510. #ifdef DEBUG
  511.         else {
  512.             debug(("RES=%06lx\n", PRes1));
  513.         }
  514. #endif
  515.         returnpacket(packet);
  516.         DosPacket = NULL;
  517.         }
  518. #ifdef DEBUG
  519.         else {
  520.         debug(("NOREP\n"));
  521.         }
  522. #endif
  523.     } /* end while (GetMsg()) */
  524.  
  525.     /*
  526.      *  Now check for an other cause of events: timer IO.
  527.      *  Unfortunately we cannot be sure that we always get a signal
  528.      *  when the timeout has elapsed, since the same message port is
  529.      *  used for other IO.
  530.      */
  531.     if (CheckIO(TimeIOReq)) {   /* Timer finished? */
  532.         debug(("TimeIOReq is finished\n"));
  533.         if (DelayState != DELAY_OFF) {
  534.         MSUpdate(0);    /* Also may switch off motor */
  535.         }
  536.     }
  537.     } /* end for (;notdone) */
  538.  
  539. #ifdef DEBUG
  540.     debug(("Can we remove ourselves? "));
  541.     Delay(50L);                 /* I wanna even see the debug message! */
  542. #endif                /* DEBUG */
  543.     Forbid();
  544.     if (OpenCount || packetsqueued()) {
  545.     Permit();
  546.     debug((" ..  not yet!\n"));
  547.     goto top;        /* sorry... can't exit     */
  548.     }
  549.     debug((" .. yes!\n"));
  550.  
  551.     /*
  552.      * Causes a new process to be created on next reference.
  553.      */
  554.  
  555.     DevNode->dn_Task = NULL;
  556.     TDRemChangeInt();
  557.     DiskRemoved();
  558.     HanCloseDown();
  559.     debug(("HanCloseDown returned. dbuninit in 2 seconds:\n"));
  560.  
  561.     /*
  562.      * Remove debug window, closedown, fall of the end of the world.
  563.      */
  564. exit:
  565. #ifdef DEBUG
  566.     Delay(100L);                /* This is dangerous! */
  567.     dbuninit();
  568. #endif                /* DEBUG */
  569.  
  570. #if 1
  571.     UnLoadSeg(DevNode->dn_SegList);     /* This is real fun. We are still */
  572.     DevNode->dn_SegList = NULL;     /* Forbid()den, fortunately */
  573. #endif
  574.  
  575.     CloseLibrary(DOSBase);
  576.  
  577.     /* Fall off the end of the world. Implicit Permit(). */
  578. }
  579.  
  580. void
  581. ChangeIntHand()
  582. {
  583. /* INDENT OFF */
  584. #asm
  585.     move.l  a6,-(sp)
  586. #endasm
  587.     DiskChanged = 1;
  588.     Signal(DosPort->mp_SigTask, PortMask);
  589. #asm
  590.     move.l  (sp)+,a6
  591. #endasm
  592. /* INDENT ON */
  593. }
  594.  
  595. /*
  596.  *  Make a new struct FileLock, for DOS use. It is put on a singly linked
  597.  *  list, which is attached to the same VolumeNode the old lock was on.
  598.  *
  599.  *  Also note that we must ALWAYS be prepared to UnLock() or DupLock()
  600.  *  any FileLocks we ever made, even if the volume in question has been
  601.  *  removed and/or inserted into another drive with another FileSystem
  602.  *  handler!
  603.  *
  604.  * DOS makes certain assumptions about LOCKS.    A lock must minimally be a
  605.  * FileLock structure, with additional private information after the
  606.  * FileLock structure.    The longword before the beginning of the structure
  607.  * must contain the length of structure + 4.
  608.  *
  609.  * NOTE!!!!! The workbench does not follow the rules and assumes it can copy
  610.  * lock structures.  This means that if you want to be workbench
  611.  * compatible, your lock structures must be EXACTLY sizeof(struct
  612.  * FileLock). Also, it sometimes uses uninitialized values for the lock mode...
  613.  */
  614.  
  615. struct FileLock *
  616. NewFileLock(msfl, fl)
  617. struct MSFileLock *msfl;
  618. struct FileLock *fl;
  619. {
  620.     struct FileLock *newlock;
  621.     DEVLIST *volnode;
  622.  
  623.     if (fl) {
  624.     volnode = BTOC(fl->fl_Volume);
  625.     } else {
  626.     volnode = VolNode;
  627.     }
  628.  
  629.     if (newlock = dosalloc((ulong)sizeof (*newlock))) {
  630.     newlock->fl_Key = (ulong) msfl;
  631.     newlock->fl_Task = DosPort;
  632.     newlock->fl_Volume = (BPTR) CTOB(volnode);
  633.     Forbid();
  634.     newlock->fl_Link = volnode->dl_LockList;
  635.     volnode->dl_LockList = (BPTR) CTOB(newlock);
  636.     Permit();
  637.     } else
  638.     error = ERROR_NO_FREE_STORE;
  639.  
  640.     return newlock;
  641. }
  642.  
  643. /*
  644.  *  This should be called before MSUnLock(), so that it may call
  645.  *  MayFreeVolNode() which then calls FreeVolNode(). A bit tricky,
  646.  *  I'm sorry for that.
  647.  */
  648.  
  649. long
  650. FreeFileLock(lock)
  651. struct FileLock *lock;
  652. {
  653.     register struct FileLock *fl;
  654.     register struct FileLock **flp;
  655.     DEVLIST       *volnode;
  656.  
  657.     volnode = (DEVLIST *)BTOC(lock->fl_Volume);
  658.     flp = (struct FileLock **) &volnode->dl_LockList;
  659.     for (fl = BTOC(*flp); fl && fl != lock; fl = BTOC(fl->fl_Link))
  660.     flp = (struct FileLock **)&fl->fl_Link;
  661.  
  662.     if (fl == lock) {
  663.     *(BPTR *)flp = fl->fl_Link;
  664.     dosfree(fl);
  665.     return DOSTRUE;
  666.     } else {
  667.     debug(("Huh?? Could not find filelock!\n"));
  668.     return DOSFALSE;
  669.     }
  670. }
  671.  
  672. /*
  673.  * Create Volume node and add to the device list.   This will
  674.  * cause the WORKBENCH to recognize us as a disk.   If we
  675.  * don't create a Volume node, Wb will not recognize us.
  676.  * However, we are a MESSYDOS: disk, Volume node or not.
  677.  */
  678.  
  679. DEVLIST        *
  680. NewVolNode(name, date)
  681. struct DateStamp *date;
  682. char *name;
  683. {
  684.     DOSINFO       *di;
  685.     register DEVLIST *volnode;
  686.     char       *volname;        /* This is my volume name */
  687.  
  688.     di = BTOC(((ROOTNODE *) DOSBase->dl_Root)->rn_Info);
  689.  
  690.     if (volnode = dosalloc((ulong)sizeof (DEVLIST))) {
  691.     if (volname = dosalloc(32L)) {
  692.         volname[0] = strlen(name);
  693.         strcpy(volname + 1, name);      /* Make sure \0 terminated */
  694.  
  695.         volnode->dl_Type = DLT_VOLUME;
  696.         volnode->dl_Task = DosPort;
  697.         volnode->dl_DiskType = IDDiskType;
  698.         volnode->dl_Name = CTOB(volname);
  699.         volnode->dl_VolumeDate = *date;
  700.         volnode->dl_MSFileLockList = NULL;
  701.  
  702.         Forbid();
  703.         volnode->dl_Next = di->di_DevInfo;
  704.         di->di_DevInfo = (long) CTOB(volnode);
  705.         Permit();
  706.     } else {
  707.         dosfree(volnode);
  708.         volnode = NULL;
  709.     }
  710.     } else {
  711.     error = ERROR_NO_FREE_STORE;
  712.     }
  713.  
  714.     return volnode;
  715. }
  716.  
  717. /*
  718.  *  Get the current VolNode a new name from the volume label.
  719.  */
  720.  
  721. void
  722. NewVolNodeName()
  723. {
  724.     if (VolNode) {
  725.     register char *volname = BTOC(VolNode->dl_Name);
  726.  
  727.     strncpy(volname + 1, Disk.vollabel.de_Msd.msd_Name, 8+3);
  728.     volname[1+8+3] = '\0';      /* Make sure \0 terminated */
  729.     ZapSpaces(volname + 1, volname + 1 + 8+3);
  730.     volname[0] = strlen(volname+1);
  731.     }
  732. }
  733.  
  734. /*
  735.  *  Get the current VolNode a new date, from the last root directory.
  736.  */
  737.  
  738. void
  739. NewVolNodeDate()
  740. {
  741.     if (VolNode) {
  742.     ToDateStamp(&VolNode->dl_VolumeDate,
  743.             Disk.vollabel.de_Msd.msd_Date,
  744.             Disk.vollabel.de_Msd.msd_Time);
  745.     }
  746. }
  747.  
  748. /*
  749.  * Remove Volume entry.  Since DOS uses singly linked lists, we must
  750.  * (ugg) search it manually to find the link before our Volume entry.
  751.  */
  752.  
  753. void
  754. FreeVolNode(volnode)
  755. DEVLIST        *volnode;
  756. {
  757.     DOSINFO       *di = BTOC(((ROOTNODE *) DOSBase->dl_Root)->rn_Info);
  758.     register DEVLIST *dl;
  759.     register void  *dlp;
  760.  
  761.     debug(("FreeVolNode %08lx\n", volnode));
  762.  
  763.     if (volnode == NULL)
  764.     return;
  765.  
  766.     dlp = &di->di_DevInfo;
  767.     Forbid();
  768.     for (dl = BTOC(di->di_DevInfo); dl && dl != volnode; dl = BTOC(dl->dl_Next))
  769.     dlp = &dl->dl_Next;
  770.     if (dl == volnode) {
  771.     *(BPTR *) dlp = dl->dl_Next;
  772.     dosfree(BTOC(dl->dl_Name));
  773.     dosfree(dl);
  774.     }
  775. #ifdef DEBUG
  776.     else {
  777.     debug(("****PANIC: Unable to find volume node\n"));
  778.     }
  779. #endif                /* DEBUG */
  780.     Permit();
  781.  
  782.     if (volnode == VolNode)
  783.     VolNode = NULL;
  784. }
  785.  
  786. /*
  787.  *  This is also called from the real handler when the last lock on a
  788.  *  volume is UnLock()ed, or the last file has been Close()d.
  789.  */
  790.  
  791. int
  792. MayFreeVolNode(volnode)
  793. DEVLIST *volnode;
  794. {
  795.     if (volnode->dl_LockList == NULL) {
  796.     FreeVolNode(volnode);
  797.     return 1;
  798.     }
  799.  
  800.     return 0;
  801. }
  802.  
  803. /*
  804.  *  Our disk has been removed. Save the FileLocks in the dl_LockList,
  805.  *  and let the handler save its MSFileLocks in the dl_MSFileLockList field.
  806.  *  If it has nothing to save, forget about the volume, and return
  807.  *  DOSTRUE.
  808.  *  There is one subtlety that MSDiskRemoved must know about:
  809.  *  If it MSUnLock()s the last lock on the volume, the VolNode is
  810.  *  deleted via FreeLockList().. MayFreeVolNode().. FreeVolNode().
  811.  *  But then there is no place anymore to put NULL in, so that needs
  812.  *  to be done first.
  813.  */
  814.  
  815. int
  816. DiskRemoved()
  817. {
  818.     debug(("DiskRemoved %08lx\n", VolNode));
  819.  
  820.     if (VolNode == NULL) {
  821.     IDDiskType = ID_NO_DISK_PRESENT;/* really business of MSDiskRemoved */
  822.     return DOSTRUE;
  823.     }
  824.  
  825.     VolNode->dl_Task = NULL;
  826.     MSDiskRemoved(&VolNode->dl_MSFileLockList);
  827.     if (VolNode == NULL) {  /* Could happen via MSDiskRemoved() */
  828.     return DOSTRUE;
  829.     }
  830.     NewVolNodeDate();       /* Fetch new date of root directory */
  831.     VolNode = NULL;
  832.     return DOSFALSE;
  833. }
  834.  
  835. /*
  836.  *  Reconstruct everything from a Volume node
  837.  */
  838.  
  839. void
  840. DiskInserted(volnode)
  841. register DEVLIST    *volnode;
  842. {
  843.     debug(("DiskInserted %08lx\n", volnode));
  844.  
  845.     VolNode = volnode;
  846.  
  847.     if (volnode) {
  848.     volnode->dl_Task = DosPort;
  849.     MSDiskInserted(&volnode->dl_MSFileLockList, volnode);
  850.     volnode->dl_MSFileLockList = NULL;
  851.     }
  852. }
  853.  
  854. DEVLIST *
  855. WhichDiskInserted()
  856. {
  857.     char name[34];
  858.     struct DateStamp date;
  859.     register DEVLIST *dl = NULL;
  860.  
  861.     if (!Inhibited && IdentifyDisk(name, &date) == 0) {
  862.     DOSINFO        *di = BTOC(((ROOTNODE *) DOSBase->dl_Root)->rn_Info);
  863.     byte           *nodename;
  864.     int        namelen = strlen(name);
  865.  
  866.     for (dl = BTOC(di->di_DevInfo); dl; dl = BTOC(dl->dl_Next)) {
  867.         nodename = BTOC(dl->dl_Name);
  868.         if (nodename[0] != namelen || strncmp(nodename+1,name,namelen))
  869.         continue;
  870.         if (dl->dl_VolumeDate == date)  /* Non-standard! Structure compare! */
  871.         break;
  872.     }
  873.  
  874.     name[31] = '\0';
  875.     if (dl == NULL)
  876.         dl = NewVolNode(name, &date);
  877.     }
  878.  
  879.     return dl;
  880. }
  881.  
  882. void
  883. DiskChange()
  884. {
  885.     debug(("DiskChange\n"));
  886.     DiskChanged = 0;
  887.     DiskRemoved();
  888.     DiskInserted(WhichDiskInserted());
  889. }
  890.  
  891. int
  892. CheckRead(lock)
  893. struct FileLock *lock;
  894. {
  895.     if (lock && BTOC(lock->fl_Volume) != VolNode)
  896.     error = ERROR_DEVICE_NOT_MOUNTED;
  897.     else if (IDDiskType == ID_NO_DISK_PRESENT)
  898.     error = ERROR_NO_DISK;
  899.     else if (IDDiskType != ID_DOS_DISK)
  900.     error = ERROR_NOT_A_DOS_DISK;
  901.  
  902.     return error;
  903. }
  904.  
  905. int
  906. CheckWrite(lock)
  907. struct FileLock *lock;
  908. {
  909.     if (lock && BTOC(lock->fl_Volume) != VolNode)
  910.     error = ERROR_DEVICE_NOT_MOUNTED;
  911.     else if (IDDiskType == ID_NO_DISK_PRESENT)
  912.     error = ERROR_NO_DISK;
  913.     else if (IDDiskType != ID_DOS_DISK)
  914.     error = ERROR_NOT_A_DOS_DISK;
  915.     else if (IDDiskState == ID_VALIDATING)
  916.     error = ERROR_DISK_NOT_VALIDATED;
  917.     else if (IDDiskState != ID_VALIDATED)
  918.     error = ERROR_DISK_WRITE_PROTECTED;
  919.  
  920.     return error;
  921. }
  922.  
  923. #ifdef DEBUG
  924.             /*    DEBUGGING            */
  925. PORT *Dbport;        /*    owned by the debug process    */
  926. PORT *Dback;        /*    owned by the DOS device driver    */
  927. short DBEnable;
  928.  
  929. /*
  930.  *  DEBUGGING CODE.    You cannot make DOS library calls that access other
  931.  *  devices from within a DOS device driver because they use the same
  932.  *  message port as the driver.  If you need to make such calls you must
  933.  *  create a port and construct the DOS messages yourself.  I do not
  934.  *  do this.  To get debugging info out another PROCESS is created to which
  935.  *  debugging messages can be sent.
  936.  */
  937.  
  938. extern void debugproc();
  939.  
  940. dbinit()
  941. {
  942.     TASK *task = FindTask(NULL);
  943.  
  944.     Dback = CreatePort("MSH:Dback", -1L);
  945.     CreateProc("MSH_DB", (long)task->tc_Node.ln_Pri+1, CTOB(debugproc), 4096L);
  946.     WaitPort(Dback);                                /* handshake startup    */
  947.     GetMsg(Dback);                                  /* remove dummy msg     */
  948.     DBEnable = 1;
  949.     dbprintf("Debugger running V1.10\n");
  950. }
  951.  
  952. dbuninit()
  953. {
  954.     MSG killmsg;
  955.  
  956.     if (Dbport) {
  957.     killmsg.mn_Length = 0;        /*    0 means die        */
  958.     PutMsg(Dbport,  &killmsg);
  959.     WaitPort(Dback);            /*  He's dead jim!      */
  960.     GetMsg(Dback);
  961.     DeletePort(Dback);
  962.  
  963.     /*
  964.      *  Since the debug process is running at a greater priority, I
  965.      *  am pretty sure that it is guarenteed to be completely removed
  966.      *  before this task gets control again.  Still, it doesn't hurt...
  967.      */
  968.  
  969.     Delay(50L);                 /*  ensure he's dead    */
  970.     }
  971. }
  972.  
  973. dbprintf(a,b,c,d,e,f,g,h,i,j)
  974. long a,b,c,d,e,f,g,h,i,j;
  975. {
  976.     struct {
  977.     MSG    msg;
  978.     char    buf[256];
  979.     } msgbuf;
  980.     register MSG *msg = &msgbuf.msg;
  981.     register long len;
  982.  
  983.     if (Dbport && DBEnable) {
  984.     sprintf(msgbuf.buf,a,b,c,d,e,f,g,h,i,j);
  985.     len = strlen(msgbuf.buf)+1;
  986.     msg->mn_Length = len;    /*  Length NEVER 0  */
  987.     PutMsg(Dbport, msg);
  988.     WaitPort(Dback);
  989.     GetMsg(Dback);
  990.     }
  991. }
  992.  
  993. /*
  994.  *  BTW, the DOS library used by debugmain() was actually opened by
  995.  *  the device driver.
  996.  */
  997.  
  998. debugmain()
  999. {
  1000.     register MSG *msg;
  1001.     register long len;
  1002.     register void *fh;
  1003.     void *fh2;
  1004.     MSG DummyMsg;
  1005.  
  1006.     Dbport = CreatePort("MSH:Dbport", -1L);
  1007.     fh = Open("CON:0/10/640/190/FileSystem debug", MODE_NEWFILE);
  1008.     fh2 = Open("PAR:", MODE_OLDFILE);
  1009.     PutMsg(Dback, &DummyMsg);
  1010.     for (;;) {
  1011.     WaitPort(Dbport);
  1012.     msg = GetMsg(Dbport);
  1013.     len = msg->mn_Length;
  1014.     if (len == 0)
  1015.         break;
  1016.     --len;                /*    Fix length up    */
  1017.     if (DBEnable & 1)
  1018.         Write(fh, msg+1, len);
  1019.     if (DBEnable & 2)
  1020.         Write(fh2, msg+1, len);
  1021.     PutMsg(Dback, msg);
  1022.     }
  1023.     Close(fh);
  1024.     Close(fh2);
  1025.     DeletePort(Dbport);
  1026.     PutMsg(Dback, msg);             /*  Kill handshake  */
  1027. }
  1028.  
  1029. /*
  1030.  *  The assembly tag for the DOS process:  CNOP causes alignment problems
  1031.  *  with the Aztec assembler for some reason.  I assume then, that the
  1032.  *  alignment is unknown.  Since the BCPL conversion basically zero's the
  1033.  *  lower two bits of the address the actual code may start anywhere
  1034.  *  within 8 bytes of address (remember the first longword is a segment
  1035.  *  pointer and skipped).  Sigh....  (see CreateProc() above).
  1036.  */
  1037.  
  1038. #asm
  1039.     public    _debugproc
  1040.     public    _debugmain
  1041.  
  1042.     cseg
  1043. _debugproc:
  1044.     nop
  1045.     nop
  1046.     nop
  1047.     nop
  1048.     nop
  1049.     movem.l D2-D7/A2-A6,-(sp)
  1050.     jsr    _debugmain
  1051.     movem.l (sp)+,D2-D7/A2-A6
  1052.     rts
  1053. #endasm
  1054.  
  1055. #endif                /* DEBUG */
  1056.